package br.ufrgs.dbproject.sax;

import java.util.Stack;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.ext.DefaultHandler2;

import br.ufrgs.dbproject.PathBuilder;
import br.ufrgs.dbproject.pathcache.CacheEntry;
import br.ufrgs.dbproject.persistence.DataSource;

public class SaxParserHandler extends DefaultHandler2 {

	private Stack<Node> nodesStack;
	
	private final PathBuilder pathBuilder;

	private final DataSource dataSource;

	private final TextBuilder textBuilder;

	public SaxParserHandler(EmptyNode emptyNode, PathBuilder pathBuilder, DataSource dataSource, TextBuilder textBuilder) {
		
		this.pathBuilder = pathBuilder;
		this.dataSource = dataSource;
		this.textBuilder = textBuilder;

		nodesStack = new Stack<Node>();
		nodesStack.push(emptyNode);
	}

	@Override
	public void startDocument() throws SAXException {
		
		int documentID = nodesStack.peek().getDocumentID();
		dataSource.saveDocument(documentID);
	}
	
	@Override
	public void characters(char[] ch, int start, int length) throws SAXException {
		textBuilder.write(ch, start, length);
	}
	
	@Override
	public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {

		textBuilder.activate();
		
		CacheEntry cachedPath = pathBuilder.append(localName);
		
		if (!cachedPath.wasFetched()) {
			dataSource.save(cachedPath);
		}
		
		Node parent = nodesStack.peek();
		Node child = parent.createChild(cachedPath, localName, attributes);
		
		nodesStack.push(child);
	}
	
	@Override
	public void endElement(String uri, String localName, String qName) throws SAXException {
		
		// TODO NumScheme should update node parent size somehow...
		
		Node node = nodesStack.pop();
		node.setText(textBuilder.getText());
		dataSource.save(node);
		
		textBuilder.deactivate();
		pathBuilder.removeTail();
	}
	
	public void endDocument() throws SAXException {
		dataSource.flush();
	}
	
	protected void setNodesStack(Stack<Node> nodesStack) {
		this.nodesStack = nodesStack;
	}
	
	public Stack<Node> getNodesStack() {
		return nodesStack;
	}
}
